<!DOCTYPE html>
<html lang="zh-CN">

  
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="utf-8">
  <meta name="author" content="董沅鑫, yuanxin.me@gmail.com">
  
  
  
  <title>使用微软的图片识别api读取HK身份证信息 | 您自己的网站标题</title>

  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  
    <meta name="keywords" content="AXIOS,坑,axios.get,">
  

  <script>
    console.log('\n%c Hexo-theme-bmw v4.0 ' + '%c 🎉 https://github.com/dongyuanxin/theme-bmw 🎉\n' + '\n%c View demo online ' + '%c 🔍 https://godbmw.com/ 🔍  \n' , 'color: #fadfa3; background: #030307; padding:3px 0;', '', 'color: #fadfa3; background: #030307; padding:3px 0;', '');
  </script>

  
    <meta name="description" content="您自己的网站描述">
  

  

  
    <link rel="icon" href="/images/favicon.ico">
    <link rel="apple-touch-icon" href="/images/touch-icon.png">
  

  <link href="https://cdn.bootcss.com/fancybox/3.5.2/jquery.fancybox.min.css" rel="stylesheet">
  <link rel="stylesheet" href="/sydblog/css/base.css">
<link rel="stylesheet" href="/sydblog/icon/iconfont.css">
<link rel="stylesheet" href="/sydblog/css/github-markdown.css">
<link rel="stylesheet" href="/sydblog/css/highlight.css">

  <script src="/sydblog/js/util.js"></script>
<script src="/sydblog/js/valine.min.js"></script>

  

  
    <link href="https://cdn.bootcss.com/aplayer/1.10.1/APlayer.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/aplayer/1.10.1/APlayer.min.js" async></script>
  

  
    <link href="https://cdn.bootcss.com/social-share.js/1.0.16/css/share.min.css" rel="stylesheet">
  
  
  <script src="//cdn.bootcss.com/jquery/3.3.1/jquery.min.js" async></script>
  
  
    <script src="//cdn.jsdelivr.net/npm/leancloud-storage@3.11.0/dist/av-min.js"></script>
  

</head>

  <body>

    

    <div id="app">

      <div class="header-wrap">
  <header>
    <div class="site-brand">
      <div class="site-title">
        <a href="/sydblog/">邵亚东博客</a>
      </div>
    </div>
    <nav class="site-navigation">
      <ul class="nav-menu">
      
        <li class="nav-item" data-path="/">
          
            <a href="/sydblog/" target="_self">
              主页
            </a>
          
        </li>
      
        <li class="nav-item" data-path="/archives/">
          
            <a href="/sydblog/archives/" target="_self">
              归档
            </a>
          
        </li>
      
        <li class="nav-item" data-path="/categories/">
          
            <a href="/sydblog/categories/" target="_self">
              分类
            </a>
          
        </li>
      
        <li class="nav-item" data-path="/tags/">
          
            <a href="/sydblog/tags/" target="_self">
              标签
            </a>
          
        </li>
      
        <li class="nav-item" data-path="/friends/">
          
            <a href="/sydblog/friends/" target="_self">
              友链
            </a>
          
        </li>
      
        <li class="nav-item" data-path="/about/">
          
            <a href="/sydblog/about/" target="_self">
              关于
            </a>
          
        </li>
      
        <li class="nav-item" data-path="">
          
            <a href="javascript:void(0);" v-else="">下拉菜单</a>
            <ul class="nav-menu--dropdown">
              
                <li>
                  <a href="https://github.com/dongyuanxin" target="_blank">
                    Github
                  </a>
                </li>
              
                <li>
                  <a href="https://www.zhihu.com/people/godbmw/activities" target="_blank">
                    知乎
                  </a>
                </li>
              
            </ul>
          
        </li>
      
      </ul>
    </nav>
    <i class="iconfont icon-menu"></i>
  </header>
</div>

<script>
  let links = document.querySelectorAll('.nav-item');
  for(let link of links){
    let childrenLink = link.querySelector('ul');
    link.addEventListener('mouseenter', () => {
      if(childrenLink) {
        childrenLink.className = "nav-menu--dropdown active";
      }
    })
    link.addEventListener('mouseleave', () => {
      if(childrenLink) {
        childrenLink.className = "nav-menu--dropdown";
      }
    })
  }
  let rootRealPath = getRealPath(window.location.pathname, true);
  for(let link of links) {
    let linkPath = link.getAttribute("data-path");
    if(linkPath && getRealPath(linkPath, true) === rootRealPath) {
      link.className = "nav-item hover";
    }
  }

  let iconMenu = document.querySelector("i.iconfont.icon-menu"),
    iconMenuClicked = false;
  let navDOM = document.querySelector("nav.site-navigation");
  iconMenu.addEventListener("click", () => {
    iconMenuClicked 
      ? navDOM.className = "site-navigation active"
      : navDOM.className = "site-navigation";
    iconMenuClicked = !iconMenuClicked;
  })
</script>

      








<div class="container post-index">

  

<div class="post">
  <h1 class="article-title">
    <span>使用微软的图片识别api读取HK身份证信息</span>
  </h1>
  <div class="article-top-meta">
    <span>
      发布 : 
      2019-01-21
    </span>
    
      <span>
        分类 : 
          <a href="/sydblog/categories/AXIOS/">
            AXIOS
          </a>
      </span>
    
    
      <span>
        浏览 : <span class="article-timer" data-identity="axios的get请求坑"></span>
      </span>
    
  </div>

  

  <div class="article-content">
    <div class="markdown-body">
      <h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>项目要求能够自动识别身份证信息</p>
<h2 id="方案"><a href="#方案" class="headerlink" title="方案"></a>方案</h2><ol>
<li>使用microsoft的图片识别api, 处理返回的图片信息.(免费的api只有7天, 7天之后需要注册microsoft azure账号)</li>
<li>使用google的图片识别api, 处理返回的图片信息. (需要注册google cloud账号, 然而信用卡区域并没有中国, 并没有试)</li>
</ol>
<h2 id="注册microsoft-azure账号并创建资源"><a href="#注册microsoft-azure账号并创建资源" class="headerlink" title="注册microsoft azure账号并创建资源"></a>注册microsoft azure账号并创建资源</h2><ol>
<li>点击”了解计算机视觉api”</li>
<li>点击免费Azure账户”注册”</li>
<li>点击”免费开始”</li>
<li>信用卡信息</li>
<li>然后扣了我两次钱, 一次10块RMB, 一次1美元.. (很无语)</li>
</ol>
<p>主页面: 点击创建资源<br><img src="/sydblog/2019/01/21/axios的get请求坑/WX20190121-181114.png" title="This is an example image"></p>
<p>选择AI + 机器学习 -&gt; 计算器视觉<br><img src="/sydblog/2019/01/21/axios的get请求坑/WX20190121-181327.png" title="This is an example image"></p>
<p>然后输入必填信息, 点新建</p>
<p>然后在’所有资源’这里就能看到了.<br><img src="/sydblog/2019/01/21/axios的get请求坑/WX20190121-181523.png" title="This is an example image"></p>
<p>点进去, 你能看到keys, 能看到key1, key2, 我目前只用了key1<br><img src="/sydblog/2019/01/21/axios的get请求坑/WX20190121-181622.png" title="This is an example image"></p>
<p>里面有什么overview , 活动日志啊, 访问控制啊, 可以自己点开看看.</p>
<h2 id="测试图片"><a href="#测试图片" class="headerlink" title="测试图片"></a>测试图片</h2><img src="/sydblog/2019/01/21/axios的get请求坑/HKID.jpg" title="This is an example image">
<h2 id="代码实现-这个已经废弃-最终代码请看下面"><a href="#代码实现-这个已经废弃-最终代码请看下面" class="headerlink" title="代码实现 (这个已经废弃, 最终代码请看下面:):"></a>代码实现 (这个已经废弃, 最终代码请看下面:):</h2><p>我这里编写了一个function来处理, 具体代码如下, 坑有注释</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">uploadHandler = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">this</span>.startLoading();</span><br><span class="line">    <span class="comment">//axios.post('https://westus2.api.cognitive.microsoft.com/vision/v2.0/ocr?language=unk&amp;detectOrientation=true', </span></span><br><span class="line">    axios.post(<span class="string">'https://westus2.api.cognitive.microsoft.com/vision/v2.0/recognizeText?mode=Printed'</span>, </span><br><span class="line">    <span class="keyword">this</span>.state.selectedFile,<span class="comment">//这里是一个文件数据</span></span><br><span class="line">    &#123;</span><br><span class="line">      headers:&#123;</span><br><span class="line">        <span class="string">"Content-Type"</span>:<span class="string">"application/octet-stream"</span>,</span><br><span class="line">        <span class="string">"Ocp-Apim-Subscription-Key"</span>:<span class="string">"xxxxxxxxxxxxxxxxxxxxxx"</span><span class="comment">//这里是我的key1</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    ).then(<span class="function">(<span class="params">response</span>) =&gt;</span> &#123;</span><br><span class="line">    	<span class="comment">//打印出来看, 在response.headers.operation-location存的是结果url</span></span><br><span class="line">    	<span class="comment">//我这里直接把url传给下一个then方法.</span></span><br><span class="line">    	<span class="comment">//坑在这里, 不能直接使用resolve, 不然就会从path这里加载进来.</span></span><br><span class="line">    	<span class="comment">//要使用Promise.resolve方法</span></span><br><span class="line">      <span class="comment">//return resolve(response.headers["operation-location"]);</span></span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">Promise</span>.resolve(response.headers[<span class="string">"operation-location"</span>]);</span><br><span class="line">    &#125;).then(<span class="function">(<span class="params">operationLocation</span>) =&gt;</span> &#123;</span><br><span class="line">    	<span class="comment">//坑就在这里, 传过来的多了一个'/', 使用Promise.resolve就不会多一个'/'</span></span><br><span class="line">    	<span class="comment">//导致get的时候会把localhost:8080自动添加到这个前面.</span></span><br><span class="line">      axios.get(operationLocation,&#123;</span><br><span class="line">        headers:&#123;</span><br><span class="line">          <span class="string">"Ocp-Apim-Subscription-Key"</span>:<span class="string">"xxxxxxxxxxxxxxxxxxxxxx"</span><span class="comment">//这里是我的key1</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;).then(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(res);</span><br><span class="line">        <span class="comment">//这里应该调用setInterval循环去查询是否处理完毕.</span></span><br><span class="line">        <span class="comment">//this.updateInfo(response.data);</span></span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">error</span>) =&gt;</span> &#123;</span><br><span class="line">      alert(error);</span><br><span class="line">      <span class="keyword">this</span>.setState(&#123; <span class="attr">loading</span>: <span class="literal">false</span> &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>
<h2 id="最终代码实现"><a href="#最终代码实现" class="headerlink" title="最终代码实现"></a>最终代码实现</h2><p>使用axios.all / axios.spread方法来执行多个请求</p>
<ol>
<li>定义调用orc api的方法</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//调用microsoft ocr api</span></span><br><span class="line">  callOcrApi = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> axios.post(<span class="string">'https://westus2.api.cognitive.microsoft.com/vision/v2.0/ocr?language=zh-Hant&amp;detectOrientation=true'</span>, </span><br><span class="line">    <span class="keyword">this</span>.state.selectedFile,</span><br><span class="line">    &#123;</span><br><span class="line">      headers:&#123;</span><br><span class="line">        <span class="string">"Content-Type"</span>:<span class="string">"application/octet-stream"</span>,</span><br><span class="line">        <span class="string">"Ocp-Apim-Subscription-Key"</span>:apikey</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;;</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>定义调用recognizeText api的方法</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//调用microsoft新版图片识别api, 仅支持英文</span></span><br><span class="line">callRecognizeTextApi = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> axios.post(<span class="string">'https://westus2.api.cognitive.microsoft.com/vision/v2.0/recognizeText?mode=Printed'</span>, </span><br><span class="line">  <span class="keyword">this</span>.state.selectedFile,</span><br><span class="line">  &#123;</span><br><span class="line">    headers:&#123;</span><br><span class="line">      <span class="string">"Content-Type"</span>:<span class="string">"application/octet-stream"</span>,</span><br><span class="line">      <span class="string">"Ocp-Apim-Subscription-Key"</span>:apikey</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<ol start="3">
<li>同时调用两个请求</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">axios.all([<span class="keyword">this</span>.callOcrApi(), <span class="keyword">this</span>.callRecognizeTextApi()]).then(axios.spread(<span class="function">(<span class="params">ocrResp, recognizeResp</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// 上面两个请求都完成后，才执行这个回调方法</span></span><br><span class="line">      <span class="comment">//处理第一个api返回的数据, 仅处理中文名字</span></span><br><span class="line">      <span class="keyword">this</span>.handlerChiName(ocrResp.data);</span><br><span class="line">      <span class="comment">//将第二个api返回的继续执行</span></span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">Promise</span>.resolve(recognizeResp.headers[<span class="string">"operation-location"</span>]);</span><br><span class="line">    &#125;))</span><br><span class="line">    .then(<span class="function">(<span class="params">operationLocation</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">this</span>.setState(&#123;<span class="attr">operationLocation</span>: operationLocation&#125;);</span><br><span class="line">      <span class="keyword">this</span>.interval = setInterval(<span class="function"><span class="params">()</span>=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.getOperationLocation();<span class="comment">//这里是调用recognizeText get api获取处理结果数据</span></span><br><span class="line">      &#125;,<span class="number">3000</span>);</span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function">(<span class="params">error</span>) =&gt;</span> &#123;</span><br><span class="line">      alert(error);</span><br><span class="line">      <span class="keyword">this</span>.setState(&#123; <span class="attr">loading</span>: <span class="literal">false</span> &#125;);</span><br><span class="line">    &#125;);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>这里的axios.spread方法可以将多个请求的response分隔开, 这样非常方便的分别处理返回数据.</p>
</blockquote>
<ol start="4">
<li>具体效果就是中文名会先显示出来, 然后才会显示英文的信息.<img src="/sydblog/2019/01/21/axios的get请求坑/microsoftOcr.gif" title="This is an example image">
</li>
</ol>
    </div>
  </div>
  
  
  
    <div class="social-share" style="margin-top: -2rem" data-wechat-qrcode-title="<p>微信扫一扫</p>" data-wechat-qrcode-helper="<p>微信右上角, 扫一扫分享</p>" data-sites="qq, wechat, weibo">
  <span style="color: #6b7487; font-size: 1.4rem;">分享到: </span>
</div>
<script src="https://cdn.bootcss.com/social-share.js/1.0.16/js/social-share.min.js" async></script>
  

  

  <div class="article-footer">
    <div class="article-meta pull-left">
      <span>
        
          <i class="iconfont icon-06tags"></i>标签: 
          
          <span class="span--tag">
            <a href="/sydblog/tags/坑/">
              #坑
            </a>
          </span>
          
          <span class="span--tag">
            <a href="/sydblog/tags/axios-get/">
              #axios.get
            </a>
          </span>
          
        
      </span>
    </div>
    <div class="article-meta pull-right">
    </div>
  </div>
</div>


  <aside id="sidebar">
    <p id="sidebar-header"></p>
    <ol id="sidebar-toc"></ol>
  </aside>
  <script async>setTimeout(generateToc, 10);</script>


  <nav class="post-navigation">
    
      <div class="nav-pre">
        <i class="iconfont icon-prev"></i>
        上一篇:
        <a href="/sydblog/2019/01/21/IOS沙盒文件查看/" target="_self">IOS沙盒文件查看</a>
      </div>
    
    
      <div class="nav-next">
        下一篇:
        <a href="/sydblog/2019/03/05/关于nodejs零碎记录/" target="_self">关于nodejs零碎记录</a>
        <i class="iconfont icon-next"></i>
      </div>
    
  </nav>

   

  
    <script defer>
const valineAPI = (() => {
  try {
    AV.init("Hyq9wkH495DgNHWhDQCOfQSp-gzGzoHsz", "WaR7nrzhliHj9aVwdQzkdlGd");
  } catch(error) {}
  const isExist = (identity) => {
    identity = identity || getRealPath();
    let query = new AV.Query('Timer');
    return new Promise((resolve, reject) => {
      query.equalTo("identity", identity);
      query.find().then(results => {
        resolve(results.length > 0);
      }, error => reject(error));
    })
  }

  const _get = (identity) => {
    let query = null;
    if(identity && identity instanceof Array){
      let querys = [];
      for(let i = 0; i < identity.length; ++i) {
        querys[i] = new AV.Query('Timer');
        querys[i].equalTo('identity', identity[i]);
      }
      query = AV.Query.or.apply(null ,querys);
    } else {
      identity = identity || getRealPath();
      query = new AV.Query("Timer");
      query.equalTo("identity", identity);
    }

    return new Promise((resolve, reject) => {
      query.find()
      .then(results => resolve(results))
      .catch(error => reject(error))
    })
  }

  const create = (identity) => {
    identity = identity || getRealPath();
    return new Promise((resolve, reject) => {
      let Todo = AV.Object.extend('Timer');
      let todo = new Todo();
      todo.set("times", 1);
      todo.set("identity", identity);
      todo.save().then(res => resolve(true), error => reject(error));
    })
  }

  const update = (identity) => {
    identity = identity || getRealPath();
    return new Promise((resolve, reject) => {
      let query = new AV.Query('Timer');
      query.equalTo("identity", identity);
      query.find().then(todos => {
        todos.forEach(todo => {
          todo.set("times", todo.attributes.times + 1);
        });
        return AV.Object.saveAll(todos);
      }).then(todos => resolve(true), error => reject(error));
    })
  }

  return {
    isExist,
    _get,
    update,
    create
  }
})()

const calcAndWriteTimes = () => {
  let isPost = true;

  let timerAllDOM = document.querySelectorAll(".article-timer");

  if(isPost) {
    let identity = timerAllDOM[0].getAttribute("data-identity");
    valineAPI.isExist(identity)
    .then(exist => {
      if(exist) {
        return valineAPI.update(identity);
      }
      return new Promise(resolve => resolve(true));
    })
    .then( succuess => valineAPI._get(identity))
    .then( result => timerAllDOM[0].innerText = result[0].attributes.times)
    .catch(error => console.log(error.message))
    return ;
  }

  let timerDOMCache = {};

  for(let timerDOM of timerAllDOM) {
    let identity = timerDOM.getAttribute("data-identity");
    if(timerDOMCache.hasOwnProperty(identity)){
      timerDOMCache[identity].dom.push(timerDOM);
    }else{
      timerDOMCache[identity] = {
        dom: [timerDOM],
        times: undefined
      };
    }
  }

  let identities = Object.keys(timerDOMCache);
  valineAPI._get(identities).then(results => {
    for(let result of results) {
      let {identity, times} = result.attributes;
      timerDOMCache[identity].times = times;
      timerDOMCache[identity].dom.map(item => item.innerText = times);
    }
    for(let identity of identities) {
      if(timerDOMCache[identity].times){
        continue;
      }
      timerDOMCache[identity].dom.map(item => item.innerText = 1);
      valineAPI.create(identity);
    }
  }).catch(error => console.log(error.message))
}

if(true){
  calcAndWriteTimes();
}
</script>
   

</div>


      <footer>
  <p class="site-info">
    博客已萌萌哒运行<span id="time-to-now"></span><span class="my-face">(●'◡'●)ﾉ♥</span>
    <br>
    Theme - <a href="https://github.com/dongyuanxin/theme-bmw">BMW</a> | Made With 💗 | Powered by <a href="https://godbmw.com/">GodBMW</a>
    <br>
    
  </p>
</footer>



<script>
const timeToNowDOM = document.querySelector("#time-to-now");
const startTimestamp = new Date(2019, 0, 16).getTime();

const updateTimeStr = () => {
  let offset = parseInt(
      (new Date().getTime() - startTimestamp) / 1000,
      10
    ),
    day = Math.floor(offset / 86400),
    hour = Math.floor((offset % 86400) / 3600),
    minute = Math.floor(((offset % 86400) % 3600) / 60),
    second = Math.floor(((offset % 86400) % 3600) % 60);
  timeToNowDOM.innerHTML =
    day + "天" + hour + "小时" + minute + "分钟" + second + "秒";
  setTimeout(updateTimeStr, 500);
}

setTimeout(updateTimeStr, 500);
</script>


      <div class="back-to-top hidden">
  <span>
    <i class="iconfont icon-60"></i><span></span>%
  </span>
</div>

<script>
const updateIconToTop = percent => {
  let dom = document.querySelector(".back-to-top span span");
  dom.innerText = percent;
  if(percent < 1) {
    document.querySelector(".back-to-top").className = "back-to-top hidden";
  } else {
    document.querySelector(".back-to-top").className = "back-to-top";
  }
}

const handleScoll = () => {
  let isRunning = false;
  return () => {
    if (isRunning) return;
    isRunning = true;
    window.requestAnimationFrame(timestamp => {
      let scrollTop =
          document.documentElement.scrollTop || document.body.scrollTop,
        scrollHeight =
          document.documentElement.scrollHeight ||
          document.body.scrollHeight,
        clientHeight =
          document.documentElement.clientHeight ||
          document.body.clientHeight;
      isRunning = false;
      if (scrollTop <= 1) {
        updateIconToTop(0);
        return;
      }
      if (scrollTop + clientHeight >= scrollHeight) {
        updateIconToTop(100);
      } else {
        updateIconToTop(parseInt(
          100 * scrollTop / (scrollHeight - clientHeight),
          10
        ));
      }
    });
  };
}

const backToTop = () => {
  let scrollTop =
      document.documentElement.scrollTop || document.body.scrollTop,
    delay = 10,
    time = 200;
  if (scrollTop <= 20) {
    document.documentElement.scrollTop = 0;
    document.body.scrollTop = 0;
    return;
  }
  let step = Math.ceil(scrollTop * delay / time);
  let timer = setInterval(() => {
    scrollTop =
      document.documentElement.scrollTop || document.body.scrollTop;
    if (scrollTop - step <= 0) {
      document.documentElement.scrollTop = 0;
      document.body.scrollTop = 0;
      clearInterval(timer);
    } else {
      document.documentElement.scrollTop = scrollTop - step;
      document.body.scrollTop = scrollTop - step;
    }
  }, delay);
}

document.addEventListener("scroll", handleScoll(), false);

document.querySelector(".back-to-top").addEventListener("click", backToTop, false);

</script>

    </div>

    
      <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" async></script>
<script>
  (() => {
    const mathjaxConfig = {
      showProcessingMessages: false, //关闭js加载过程信息
      messageStyle: "none", //不显示信息
      jax: ["input/TeX", "output/HTML-CSS"],
      tex2jax: {
        inlineMath: [["$", "$"], ["\\(", "\\)"]], //行内公式选择符
        displayMath: [["$$", "$$"], ["\\[", "\\]"]], //段内公式选择符
        skipTags: ["script", "noscript", "style", "textarea", "pre", "code", "a"] //避开某些标签
      },
      "HTML-CSS": {
        availableFonts: ["STIX", "TeX"], //可选字体
        showMathMenu: false //关闭右击菜单显示
      }
    }

    let mathjaxInterval = setInterval(() => {
      if(!window.MathJax){
        return;
      }
      window.MathJax.Hub.Config(mathjaxConfig)
      window.MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById('app')])

      clearInterval(mathjaxInterval)
    }, 10)    
  })()
</script>
    

    <script src="https://cdn.bootcss.com/fancybox/3.5.2/jquery.fancybox.min.js" async></script>
<script async>
  let fancyTimer = setInterval(function(){
    if(!window.$){
      return;
    }
    $(document).ready(function() {
      $(".post img").each(function () {
        if($(this).parent().get(0).tagName.toLowerCase() === "a") {
          return;
        }
        // $(this).attr("data-fancybox", "gallery"); // if you add 'data-fancybox', img will display after showed
        var element = document.createElement("a");
        $(element).attr("data-fancybox", "gallery");
        $(element).attr("href", $(this).attr("src"));
        $(this).wrap(element);
      });
      
      clearInterval(fancyTimer);
    });
  }, 10);
</script>

    
  </body>

</html>
